// 11-散列4 Hashing - Hard Version
#include <stdio.h>
#include <stdlib.h>

/* MGraph ======================================================*/
// 定义权重的最大值
#define MaxWeight 0x7FFF
// 无路径
#define Connectionless -1
// 有向图, 无向图
#define DirectedGraph 1
#define UndirectedGraph 0

// 权重类型
typedef int WeightType;
typedef struct Edge Edge;
struct Edge {
    int v, w;
    WeightType weight;
};

typedef struct MGraph MGraph;
struct MGraph {
    int directed; // 1-有向图，0-无向图
    int defaultWeight; // 默认的无连接的权重
    int vertexNum; // 顶点数
    int edgeNum;   // 边数
    WeightType **g; // 邻接矩阵
};

MGraph *createGraph(int directed, int defaultWeight, int vertexNum) {
    MGraph* g = (MGraph*)calloc(sizeof(MGraph), 1);
    g->directed = directed;
    g->defaultWeight = defaultWeight;
    g->vertexNum = vertexNum;
    g->edgeNum = 0;
    // 初始化邻接矩阵
    g->g = (WeightType**) malloc(sizeof(WeightType*) * vertexNum);
    for (int v=0; v < g->vertexNum; v++) {
        g->g[v] = (WeightType*) malloc(sizeof(WeightType) * vertexNum);
        for (int w=0; w < g->vertexNum; w++) {
            g->g[v][w] = defaultWeight;
        }
    }
    return g;
}

void free2D(int **a, int n) {
    for (int i=0; i<n; i++) {
        free(a[i]);
    }
    free(a);
}

void freeGraph(MGraph* g) {
    free2D(g->g, g->vertexNum);
    free(g);
}

// 判断图的两个顶点 v1, v2 之间是否有直接连接
int isConnection(MGraph* g, int v1, int v2) {
    return g->g[v1][v2] != g->defaultWeight;
}

void insertEdge(MGraph* g, int v1, int v2, WeightType weight) {
    g->g[v1][v2] = weight;
    if (g->directed == UndirectedGraph) {
        g->g[v2][v1] = weight;
    }
    g->edgeNum++;
}

void print2D(int **m, int n, int defaultWeight) {
    for (int i=-1; i<n; i++) {
        printf("[%3d]", i);
    }
    printf("\n");
    for (int i=0; i<n; i++) {
        printf("[%3d]", i);
        for (int j=0; j<n; j++) {
            if (m[i][j] == defaultWeight) {
                printf("    -");
            } else {
                printf("%5d", m[i][j]);
            }
        }
        printf("\n");
    }
}

void printGraph(MGraph* g) {
    printf("Graph n=%d, e=%d\n", g->vertexNum, g->edgeNum);
    print2D(g->g, g->vertexNum, g->defaultWeight);
}

/* current ===========================================*/
// 图顶点, 用于拓扑排序中的堆，按 value 排序
typedef struct {
    int v; // 顶点编号
    int value; // 顶点的值
} Vertex;

void inputVertex(Vertex vs[], int n) {
    for (int i=0; i<n; i++) {
        scanf("%d", &vs[i].value);
        vs[i].v = i;
    }
}

MGraph* buildGraph(Vertex vs[], int n) {
    MGraph* graph = createGraph(DirectedGraph, MaxWeight, n);
    for (int i=0; i < n; i++) {
        // printf("process %d\n", vs[i].value);
        if (vs[i].value < 0) {
            continue;
        }
        // 无冲突位置
        int idx1 = vs[i].value % n;
        if (i == idx1) {
            // 自己和自己不冲突
            continue;
        }
        // 从无冲突位置开始，到当前位置，在图中建立边
        int idx2 = idx1;
        if (idx2 > i) {
            for (; idx2 < n; idx2++) {
                insertEdge(graph, idx2, i, 1);
                // printf("insertEdge(%d, %d)\n", vs[idx2].value, vs[i].value);
            }
            idx2 = 0;
        }
        for (; idx2 < i; idx2++) {
            insertEdge(graph, idx2, i, 1);
            // printf("insertEdge(%d, %d)\n", vs[idx2].value, vs[i].value);
        }
    }
    return graph;
}

void printVertexs(Vertex vs[], int n) {
    for (int i=0; i<n; i++) {
        if (i != 0) {
            printf(" ");
        }
        printf("%d", vs[i].value);
    }
    printf("\n");
}

int topSort(MGraph* graph, Vertex topOrder[], Vertex vs[]);

int main() {
    int n;
    scanf("%d", &n);
    Vertex* vs = (Vertex*)calloc(n, sizeof(Vertex));
    inputVertex(vs, n);
    MGraph* graph = buildGraph(vs, n);
    // printGraph(graph);
    // printVertexs(vs, n);

    // 拓扑排序
    Vertex* topOrder = (Vertex*)calloc(n, sizeof(Vertex));
    int outn = topSort(graph, topOrder, vs);
    // 输出
    printVertexs(topOrder, outn);

    // 释放内存
    freeGraph(graph);
    free(vs);
    free(topOrder);
    return 0;
}

// 因为输出时要按值从小到大的顺序输出，所以用最小堆替换原来topSort中的队列

/* Heap ===========================================================*/
#define HeapElementType Vertex*

int VertexComparator(HeapElementType e1, HeapElementType e2) {
    // 因为默认是最大堆，所以这里要反过来
    return e2->value - e1->value;
}

// 为能直接把其他的数组直接调整为堆，这里不使用[0]存放哨兵的方法，从[0]开始存储元素
typedef struct Heap Heap;
struct Heap {
    HeapElementType* data; // 存储元素的数组
    int size; // 元素个数
    int capacity; // 最大容量
    // 堆元素比较器
    int (*comparator)(HeapElementType e1, HeapElementType e2);
};

// 从 startIdx 开始的位置向下调整，让数组变为堆
void percDown(Heap* h, int startIdx) {
    int parent, child;
    // 取出 startIdx 处存放的值
    HeapElementType temp = h->data[startIdx];
    // 向下（左右儿子）找可以正确存放 temp 的合适位置
    for (parent = startIdx; parent*2+1 < h->size; parent = child /* 顺着调整过的儿子节点继续向下 */) {
        child = parent*2+1;
        if ((child != h->size - 1) && h->comparator(h->data[child], h->data[child+1]) < 0) {
            // 有右儿子，且右儿子比较大
            child++; // 指向右儿子
        }
        if (h->comparator(temp, h->data[child]) >= 0) {
            // temp 比它的左右儿子都大，即找到了合适位置，不用再往下找了
            break;
        }
        // 把更大的子节点复制到父节点位置，即把大的数往上调
        h->data[parent] = h->data[child];
    }
    h->data[parent] = temp;
}

Heap* createHeap(int capacity, int (*comparator)(HeapElementType e1, HeapElementType e2)) {
    Heap* h = calloc(1, sizeof(Heap));
    h->data = calloc(capacity, sizeof(HeapElementType));
    h->size = 0;
    h->capacity = capacity;
    h->comparator = comparator;
    return h;
}

void freeHeap(Heap* h) {
    free(h->data);
    free(h);
}

int isEmptyHeap(Heap* h) {
    return h->size < 1;
}

int isFullHeap(Heap* h) {
    return h->size+1 > h->capacity;
}

void insertHeap(Heap* h, HeapElementType item) {
    if (isFullHeap(h)) {
        printf("Heap Full");
        return;
    }
    int i = h->size++;
    // 调整:比较item，与item的父节点（父节点下标=(i-1)/2），若大于父节点，把父节点往下移动
    for (; i > 0 && h->comparator(item, h->data[(i-1)/2]) > 0; i=(i-1)/2) {
        h->data[i] = h->data[(i-1)/2];
    }
    h->data[i] = item;
}

HeapElementType deleteHeap(Heap *h) {
    if (isEmptyHeap(h)) {
        printf("Heap Empty\n");
        HeapElementType error;
        return error;
    }
    // 取出最大的节点
    HeapElementType maxItem = h->data[0];
    // 先把最后一个节点放入第0个节点位置
    h->data[0] = h->data[--h->size];
    // 因为动了第0个位置，从0开始向下调整堆
    percDown(h, 0);
    return maxItem;
}

/* Graph topsort ===========================================*/
// 建立，并初始化顶点入度数组
int* initIndegree(MGraph* graph) {
    // 使用 calloc 方法，会把内容初始化为 0
    int* indegree = (int*) calloc(graph->vertexNum, sizeof(int));
    /* 遍历图，得到indegree[] */
    for (int j=0; j < graph->vertexNum; j++) {
        // 第 j 个节点的入度，即与第 j 列连接的边数和
        for (int i=0; i < graph->vertexNum; i++) {
            if (isConnection(graph, i, j)) {
                indegree[j]++;
            }
        }
    }
    return indegree;
}

int topSort(MGraph* graph, Vertex topOrder[], Vertex vs[]) {
    /* 对Graph进行拓扑排序,  TopOrder[]顺序存储排序后的顶点下标 */
    int* indegree = initIndegree(graph);

    Heap* heap = createHeap(graph->vertexNum, VertexComparator);
    /* 将所有入度为0的顶点入列 */
    for (int i=0; i < graph->vertexNum; i++) {
        if (indegree[i] == 0 && vs[i].value >= 0) {
            insertHeap(heap, &vs[i]);
        }
    }

    /* 下面进入拓扑排序 */ 
    int cnt = 0; 
    
    while (!isEmptyHeap(heap)) {
        /* 弹出一个入度为0的顶点 */
        Vertex* vertex = deleteHeap(heap); 
        topOrder[cnt++] = *vertex; /* 将之存为结果序列的下一个元素 */
        
        /* 对V的每个邻接点W */
        for (int w=0; w < graph->vertexNum; w++) {
            // 计算 v 的 earliest
            // 这里 w 是 v 的前序节点
            // if (isConnection(graph, w, v)) {
            //     // 有边<w, v>
            //     earliest[v] = max(earliest[v], earliest[w] + graph->g[w][v]);
            // }
            // 这里  w 是 v 的后序节点
            if (isConnection(graph, vertex->v, w)) {
                // 有边<v, w>
                --indegree[w];
                /* 若删除V使得W入度为0 */
                if (indegree[w] == 0) {
                    /* 则该顶点入列 */
                    insertHeap(heap, &vs[w]);
                }
            }
        }
    }
    free(indegree);
    freeHeap(heap);
    return cnt;
}
